package com.smsc.headend.task.engine.service.report.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.google.common.collect.Lists;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.AppName;
import com.smsc.headend.module.data.entity.ScheduleReadingEntity;
import com.smsc.headend.module.report.entity.LogReportHis;
import com.smsc.headend.task.engine.po.ScheduleReadingDataBo;
import com.smsc.headend.task.engine.service.DataConvertService;
import com.smsc.headend.task.engine.service.DataProcessService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.report.GenReportService;
import com.smsc.headend.task.engine.service.task.LogReportHisService;
import com.smsc.headend.task.engine.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GenReportServiceImpl implements GenReportService {
    @Autowired
    LogReportHisService logReportHisService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    DataConvertService dataConvertService;
    @Autowired
    private DataProcessService dataProcessService;

    @Override
    public void generateReport(Map<String, Object> params, LogReportHis logReportHis) {
        Map criteria = (Map) params.get("criteria");
        try {
            ScheduleReadingDataBo scheduleReadingDataBo = getScheduleReadingDataBo(params, criteria);
            List<ScheduleReadingEntity> collect = getCollect(scheduleReadingDataBo, params);
            String[] titles = getTitles(scheduleReadingDataBo, params);
            String[] keys = getkeyList(scheduleReadingDataBo, params);
            String type = MapUtil.getStr(criteria, "type");
            String typeName = LogReportHis.ReportType.SCHEDULE_READING.getText();
            String remoteFileGenPath =  assetManagementService.getPropertyValue("REPORT_FILE_GENERATE_PATH");
            String fileName = typeName + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS");

                ExcelUtils.writeReport(remoteFileGenPath, typeName, fileName, collect, titles, keys, type);
                logReportHisService.saveReportLog(logReportHis.getLogSeq(), null, null,null, LogReportHis.ReportHisStatus.SUCCESS.getCode(),
                        SystemClock.now() / 1000, typeName + "/", fileName + ".xlsx", null);
        } catch (IOException e) {
            log.info("IOException", e);
            logReportHisService.saveReportLog(logReportHis.getLogSeq(), null, null,null, LogReportHis.ReportHisStatus.FAILED.getCode(),
                    SystemClock.now() / 1000, null, null, e.getMessage());
        } catch (Exception e) {
            log.info("exception", e);
            logReportHisService.saveReportLog(logReportHis.getLogSeq(), null, null,null, LogReportHis.ReportHisStatus.FAILED.getCode(),
                    SystemClock.now() / 1000, null, null, e.getMessage());
        }
    }

    private ScheduleReadingDataBo getScheduleReadingDataBo(Map<String, Object> params, Map criteria) {
        try {
            List<Long> meterIds = (List<Long>) ((Map) params.get("criteria")).get("meterIds");
            List<Integer> dcuIds = (List<Integer>) ((Map) params.get("criteria")).get("dcuIds");
            if (meterIds.isEmpty() && !dcuIds.isEmpty()) {
                if(meterIds == null) {
                    meterIds = CollUtil.newArrayList();
                }
                for (Integer dcuId : dcuIds) {
                    List<Meter> meterList = assetManagementService.getMetersByDcuId(Convert.toLong(dcuId));
                    meterIds.addAll(meterList.stream().map(Meter::getMeterId).collect(Collectors.toList()));
                }
            }
            List<Long> timeRangeList = (List) criteria.get("timeRange");
            List<Long> subDataItemIds = (List) criteria.get("subDataItemArr");
            Long lpDataItemId = MapUtil.getLong(criteria, "dataGroup");
            Long startTime = timeRangeList.get(0) / 1000;
            Long endTime = timeRangeList.get(1) / 1000;
            Long[] paramMeters = Convert.toLongArray(meterIds);
            ScheduleReadingDataBo scheduleReadingDataBo = dataProcessService.lpDataPivotByOffsetAndLimit(paramMeters, lpDataItemId, Convert.toLongArray(subDataItemIds), startTime, endTime, 0, -1);

            return scheduleReadingDataBo;
        } catch (Exception e) {
            log.info("exception", e);
            return null;
        }

    }

    private String[] getTitles(ScheduleReadingDataBo scheduleReadingDataBo, Map<String, Object> params) {
        String locale = MapUtil.getStr(params, "locale");
        List<String> titleList = CollUtil.toList(dataConvertService.getI18NStr("customerSerialNumber", locale), dataConvertService.getI18NStr("time", locale));//CollUtil.toList("Customer Serial Number", "Time");
        Map<String, String> subDataItemIdName = dataConvertService.getSubDataItemIdName(Lists.newArrayList(scheduleReadingDataBo.getDataItemIds()), locale, Boolean.TRUE, AppName.GUI.toString());
        subDataItemIdName.entrySet().forEach(e -> {
            titleList.add(e.getValue());
        });
        titleList.add(dataConvertService.getI18NStr("profileStatus", locale));
        titleList.add(dataConvertService.getI18NStr("source", locale));//titleList.add("Source");
        titleList.add(dataConvertService.getI18NStr("updateTime", locale));//titleList.add("Update Time");
        return ArrayUtil.toArray(titleList, String.class);
    }

    private String[] getkeyList(ScheduleReadingDataBo scheduleReadingDataBo, Map<String, Object> params) {
        String locale = MapUtil.getStr(params, "locale");
        List<String> keyList = CollUtil.toList("customerSn", "tv");
        Map<String, String> subDataItemIdName = dataConvertService.getSubDataItemIdName(Lists.newArrayList(scheduleReadingDataBo.getDataItemIds()), locale, Boolean.TRUE, AppName.GUI.toString());
        subDataItemIdName.entrySet().forEach(e -> {
            keyList.add(e.getKey());
        });
        keyList.add("validity");
        keyList.add("src");
        keyList.add("tvUpdate");
        return ArrayUtil.toArray(keyList, String.class);
    }

    private List<ScheduleReadingEntity> getCollect(ScheduleReadingDataBo scheduleReadingDataBo, Map<String, Object> params) {
        Map criteria = (Map) params.get("criteria");
        Integer calculateRatio = MapUtil.getInt(criteria, "calculateRatio");
        List<ScheduleReadingEntity> dataList = scheduleReadingDataBo.getScheduleReadingEntityList();

        List<ScheduleReadingEntity> collect = dataList.stream().sorted((d1, d2) -> {
            String customerSn1 = MapUtil.getStr(d1, "customerSn");
            String customerSn2 = MapUtil.getStr(d2, "customerSn");
            int i = customerSn1.compareTo(customerSn2);
            if (i != 0) {
                return i;
            }
            String tv1 = MapUtil.getStr(d1, "tv");
            String tv2 = MapUtil.getStr(d2, "tv");
            return tv1.compareTo(tv2) * -1;
        }).collect(Collectors.toList());
        if (1 == calculateRatio) {
            collect = dataConvertService.convertCTVT(collect);
        }
        return collect;
    }
}
